package io.lvdaxian.mybatis08.builder.xml;

import io.lvdaxian.mybatis08.builder.BaseBuilder;
import io.lvdaxian.mybatis08.io.Resources;
import io.lvdaxian.mybatis08.session.Configuration;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.List;

/**
 * XML映射构建器
 *
 * @author lihh
 */
public class XMLMapperBuilder extends BaseBuilder {
  
  // element 元素
  private final Element element;
  // source 资源
  private final String resource;
  // 表示当前的命名空间
  private String currentNamespace;
  
  public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource) throws DocumentException {
    this(new SAXReader().read(inputStream), configuration, resource);
  }
  
  public XMLMapperBuilder(Document document, Configuration configuration, String resource) {
    super(configuration);
    this.element = document.getRootElement();
    this.resource = resource;
  }
  
  /**
   * 解析 xml 的核心方法
   *
   * @author lihh
   */
  public void parse() {
    if (configuration.isResourceLoaded(resource))
      return;
    
    // 开始解析 xml
    configurationElement(element);
    // 表示该 xml 解析过了
    configuration.addLoadedResource(resource);
    // 添加 mapper 此时的 这个currentNamespace 已经在上面 赋值过了
    configuration.addMapper(Resources.classForName(currentNamespace));
  }
  
  /**
   * 解析 元素的核心方法
   * <p>
   * 配置mapper元素
   * <mapper namespace="org.mybatis.example.BlogMapper">
   * <select id="selectBlog" parameterType="int" resultType="Blog">
   * select * from Blog where id = #{id}
   * </select>
   * </mapper>
   *
   * @param element element 元素
   * @author lihh
   */
  private void configurationElement(Element element) {
    // 从 这里拿到 namespace
    currentNamespace = element.attributeValue("namespace");
    if ("".equals(currentNamespace))
      throw new RuntimeException("Mapper's namespace cannot be empty");
    
    // todo 这里是解析 select的片段
    buildStatementFromContext(element.elements("select"));
  }
  
  /**
   * 从上下文 解析出 statement 片段
   *
   * @param list element 列表
   * @author lihh
   */
  private void buildStatementFromContext(List<Element> list) {
    // 通过遍历的方式 一个一个 片段的进行处理
    for (Element element : list) {
      // 构建 片段的 statement
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, element, currentNamespace);
      // 解析 statement
      statementParser.parseStatementNode();
    }
  }
}
